#pragma once
#include <stdlib.h>
#include <ctime>
#include <vector>
using namespace Point2DFunc;

template <class T>
class Point2D
{
public:
    T m_x, m_y;

    enum TYPE
    {
        INSIDE,
        BORDER
    };

    Point2D(const T dx = 0, const T dy = 0) : m_x(dx), m_y(dy) {}
    ~Point2D() {}

    bool SetRandomValue(const TYPE type, const int fp, const int rp)
    {
        if (0 == fp || 0 == rp ) return false;
        srand(time(0));   

        switch (type)
        {
            case INSIDE:
                m_x = (fp > 0 ? rand() % fp : - rand() % fp);
                m_y = (rp > 0 ? rand() % rp : - rand() % rp);
                break;

            case BORDER:
                int firstCase = rand() % 2;
                int secondCase = rand() % 2;

                m_x = (firstCase == 0 ? 0 : (fp > 0 ? rand() % fp : - rand() % fp));
                m_y = (secondCase == 0 ? 0 : (rp > 0 ? rand() % rp : - rand() % rp));
                break;

            default:
                return false;
        }

        return true;
    }

    bool operator<(const Point2D& p)
    {
        return !(*this <= p); 
    }

    bool operator<=(const Point2D& p)
    {
        bool firstCondition = Det(*this, p) > 0;
        T dotC1_1 = Dot(*this, Point2D(1, 1));
        T dotC1_2 = Dot(*this, Point2D(2, 2));
        T dotC2_1 = Dot(p, Point2D(1, 1));
        T dotC2_2 = Dot(p, Point2D(2, 2));
        bool secondCondition = ((Det(this, p) == 0) &&
            ((dotC1_1 * dotC1_1 + dotC1_2 * dotC1_2) < (dotC2_1 * dotC2_1 + dotC2_2 * dotC2_2)));

        return firstCondition || secondCondition;
    }
};

namespace Point2DFunc
{
    template <class T>
    inline T Det(const Point2D < T >& p1, const Point2D < T >& p2)
    {
        return (p1.m_x * p2.m_y - p1.m_y * p2.m_x); 
    }

    template <class T>
    inline T Dot(const Point2D < T >& p1, const Point2D < T >& p2)
    {
        return (p1.m_x * p2.m_x + p1.m_y * p2.m_y);
    }
    
    template <class T>
    inline int FindLexMin(const Point2D < T > *points_array, const int size)
    {
        Point2D < T > lexMin = points_array[0];  
        int res = 0;;

        for ( int i = 1; i < size; ++i)
        {
            Point2D < T > point = points_array[i];

            if (lexMin.m_x > point.m_x || (lexMin.m_y > point.m_y && lexMin.m_x == point.m_x))
            {
                lexMin = point;
                res = i;
            }
        }

        return i;
    }

    template <class T>
    void ConvSort(const Point2D < T > *points, const int size)
    {
        int pos = FindLexMin(points, size);
        
        if (pos != 0)
        {
            Point2D < T > swap = points[0];
            points[0] = points[pos];
            points[pos] = swap;
        }

        for (int i = 1; i < size; ++i)
        {
            points[i].m_x -= points[0].m_x;
            points[i].m_y -= points[0].m_y;
        }
    }
}


